---------------Microwave---------------
A 4am crack                  2018-07-29
---------------------------------------

Name: Microwave
Genre: arcade
Year: 1982
Credits: Jay P. Zimmermann, James L.
  Nitchals
Publisher: Cavalier Computer
  Corporation
Platform: Apple ][+ or later
Media: 5.25-inch disk
Sides: 1
OS: custom

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  fails halfway through

Locksmith Fast Disk Backup
  unable to read track $11;
  copy loads graphical title screen
  then hangs with the drive motor on

Passport
  finds "nibble check protection" on
  track $11, but does not apply any
  patches

Copy ][+ nibble editor
  track $11 is almost entirely sync
  bytes, no structure to speak of

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 11  START: 1800  LENGTH: 3DFF

1B80: FF FF FF FF FF FF FF FF   VIEW
1B88: FF FF FF FF FF FF FF FF
1B90: FF FF FF FF FF FF FF FF
1B98: FF FF FF FF FF FF FF FF
1BA0: FF FF FF FF FF FF FF AA  <-1BA7
1BA8: D5 E6 FD FE FF FF FF FF
1BB0: FF FF FF FF FF FF FF FF
1BB8: FF FF FF FF FF FF FF FF
1BC0: FF FF FF FF FF FF FF FF

                 --^--

Disk Fixer
  T00,S00 looks like DOS 3.3 bootloader
  (loading in low memory, at $3600+,
  like a master disk), but $3747 jumps
  to $8100 instead of the usual $1B03

Why didn't COPYA work?
  track $11 is not a standard 16-sector
  track

Why didn't Locksmith FDB work?
  probably a runtime check that checks
  the structure of track $11

Next steps:

  1. Find the runtime protection check
  2. Disable it
  3. Declare victory(*)

(*) go to the gym

                   ~

               Chapter 1
             Plus or Minus


The bootloader jumps to $8100 after
doing a multi-sector read. Looking at
the code in my favorite sector editor,
I can calculate where that resides on
disk:

                 --v--

T00,S01 ($3700)
----------- DISASSEMBLY MODE ----------
0000:8E E9 37       STX   $37E9
0003:8E F7 37       STX   $37F7
0006:A9 01          LDA   #$01
0008:8D F8 37       STA   $37F8
000B:8D EA 37       STA   $37EA
000E:AD E0 37       LDA   $37E0
0011:8D E1 37       STA   $37E1
0014:A9 02          LDA   #$02  ;track
0016:8D EC 37       STA   $37EC
0019:A9 04          LDA   #$04  ;sector
001B:8D ED 37       STA   $37ED
001E:AC E7 37       LDY   $37E7 ;=$93
0021:88             DEY
0022:8C F1 37       STY   $37F1 ;=$92

                 --^--

T02,S04 is loaded into $9200, and the
standard multi-sector read loop reads
sectors and tracks in descending order
into descending pages in memory, so...

$8100 is loaded from T01,S03.

                 --v--

T01,S03 ($8100)
----------- DISASSEMBLY MODE ----------
0000:4C 17 8A       JMP   $8A17

                 --^--

$8A00 is loaded from ... [counts on
fingers] ... T01,S0C.

                 --v--

T01,S0C ($8A00)
----------- DISASSEMBLY MODE ----------
; reset stack
0017:A2 80          LDX   #$80
0019:9A             TXS
001A:A9 00          LDA   #$00
001C:8D FC 80       STA   $80FC
001F:8D FD 80       STA   $80FD
0022:8D FE 80       STA   $80FE
0025:8D FF 80       STA   $80FF

; hi-res graphics mode
0028:2C 50 C0       BIT   $C050
002B:2C 52 C0       BIT   $C052
002E:2C 57 C0       BIT   $C057
0031:A9 FC          LDA   #$FC
0033:85 86          STA   $86
0035:A9 1F          LDA   #$1F
0037:85 87          STA   $87
0039:A9 1B          LDA   #$1B
003B:A2 0F          LDX   #$0F

; multi-sector read (not shown, loads
; the graphical title screen from disk)
003D:20 F7 89       JSR   $89F7

; track seek subroutine takes slot in X
; and target track in A (not shown, but
; hey look, we're seeking to the
; unreadable track $11, that's probably
; important)
0040:A9 11          LDA   #$11
0042:A2 60          LDX   #$60
0044:20 C9 8F       JSR   $8FC9

; do a thing (more on this in a moment)
0047:20 E8 8F       JSR   $8FE8

; compare the result
004A:CD 03 81       CMP   $8103

; good to go, jump to game code
004D:F0 13          BEQ   $0062

; subtract 2 from result
004F:38             SEC
0050:E9 02          SBC   #$02

; also an acceptable result
0052:CD 03 81       CMP   $8103
0055:F0 0B          BEQ   $0062

; add 4 to result (= original+2)
0057:18             CLC
0058:69 04          ADC   #$04

; also an acceptable result
005A:CD 03 81       CMP   $8103
005D:F0 03          BEQ   $0062

; otherwise jump back to track seek and
; try again forever
005F:4C 40 8A       JMP   $8A40

                 --^--

So we're in an infinite loop until the
subroutine at $8FE8 returns a result
that matches the value at $8103, plus
or minus 2.

At this point I have a pretty good idea
how to patch this, but let's see what
exactly we're doing at $8FE8.

                   ~

               Chapter 2
     Tautological, My Dear Watson


$8FE8 is loaded from T02,S01.

                 --v--

T02,S01 ($8F00)
----------- DISASSEMBLY MODE ----------
; hard-coded to slot 6
00E8:A9 60          LDA   #$60
00EA:8D 8C 8A       STA   $8A8C
00ED:AE 8C 8A       LDX   $8A8C

; turn on drive motor
00F0:BD 89 C0       LDA   $C089,X

; wait for it to spin up
00F3:A0 01          LDY   #$01
00F5:20 A8 FC       JSR   $FCA8
00F8:88             DEY
00F9:D0 FA          BNE   $00F5
00FB:AE 8C 8A       LDX   $8A8C

; scan for a $D5 nibble
00FE:BD 8C C0       LDA   $C08C,X
[continued on T02,S02]
0001:10 FB          BPL   $FFFE
0003:C9 D5          CMP   #$D5
0005:D0 F7          BNE   $FFFE

; count nibbles until the next $D5
0007:A0 00          LDY   #$00
0009:BD 8C C0       LDA   $C08C,X
000C:10 FB          BPL   $0009
000E:C8             INY
000F:C9 D5          CMP   #$D5
0011:D0 F6          BNE   $0009

; and again
0013:BD 8C C0       LDA   $C08C,X
0016:10 FB          BPL   $0013
0018:C8             INY
0019:C9 D5          CMP   #$D5
001B:D0 F6          BNE   $0013

; turn off drive motor
001D:BD 88 C0       LDA   $C088,X

; transfer final nibble count into A
; and return to caller
0020:98             TYA
0021:60             RTS

                 --^--

The "correct" answer, stored in $8103,
is #$4E (plus or minus 2, apparently).
But I don't even care what the correct
answer is, as long as this subroutine
matches the correct answer. So let's
make it return the correct answer:

T02,S01,$E8: change to AD038160

which translates to "LDA $8103 / RTS",
i.e. load the correct answer from the
address the caller is going to check
against, then return to the caller so
it can check the answer.

Quod erat liberandum.

---------------------------------------
A 4am crack                    No. 1779
------------------EOF------------------
